package znet

import (
	"errors"
	"fmt"
	"net"
	"zinx-new/utils"
	"zinx-new/ziface"
)

// Server, implements server interface
type Server struct {
	Name      string
	IPVersion string
	IP        string
	// bind port
	Port        int
	msgHandler  ziface.IMsgHandle
	ConnMgr     ziface.IConnManager // 连接管理
	onConnStart func(connection ziface.IConnection)
	onConnStop  func(connection ziface.IConnection)
}

func NewServer() ziface.IServer {
	s := &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4",
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.TCPPort,
		msgHandler: NewMsgHandle(),
		ConnMgr:    NewConnManager(),
	}
	return s
}

func CallBackToClient(conn *net.TCPConn, data []byte, count int) error {
	// write back
	fmt.Println("[Conn Handle] CallBackToClient  ...")
	if _, err := conn.Write(data[:count]); err != nil {
		fmt.Println("write back buf err ", err)
		return errors.New("CallBackToClient error")
	}
	return nil
}

func (s *Server) Start() {
	fmt.Printf("[START] Server listener at IP: %s, Port %d, is starting\n", s.IP, s.Port)
	fmt.Printf("[Zinx] version: %s, MaxConn: %d, MaxPacketSize: %d\n", utils.GlobalObject.Version, utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPacketSize)
	// 开启一个go去listen
	go func() {
		// start worker
		s.msgHandler.StartWorkerPool()

		// get addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr err: ", err)
			return
		}
		// listen addr
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err ", err)
			return
		}
		// listen success
		fmt.Println("start zinx server ", s.Name, " success, now listening...")

		// TODO server.go increase cid
		cid := uint32(0)
		// start server
		for {
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err ", err)
				continue
			}
			// 设置服务器最大连接控制,如果超过最大连接，那么则关闭此新的连接
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
				_ = conn.Close()
				continue
			}
			// 处理该新连接请求的 业务 方法， 此时应该有 handler 和 conn是绑定的
			dealConn := NewConnection(conn, cid, CallBackToClient, s.msgHandler, s)
			cid++
			// 处理连接业务
			go dealConn.Start()
		}
	}()
}

func (s *Server) Stop() {
	fmt.Println("[STOP] zinx server, name ", s.Name)
	// 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
	s.ConnMgr.ClearConn()
}

func (s *Server) Serve() {
	s.Start()
	// TODO handle others
	select {}
}

// 给当前服务注册一个路由业务方法，供客户端链接处理使用
func (s *Server) AddRouter(msgID uint32, router ziface.IRouter) {
	s.msgHandler.AddRouter(msgID, router)
}

// 获取管理器
func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

func (s *Server) SetOnConnStart(hookFunc func(connection ziface.IConnection)) {
	s.onConnStart = hookFunc
}

func (s *Server) SetOnConnStop(hookFunc func(connection ziface.IConnection)) {
	s.onConnStop = hookFunc
}

func (s *Server) CallOnConnStart(connection ziface.IConnection) {
	if s.onConnStart != nil {
		println("call conn start")
		s.onConnStart(connection)
	}
}
func (s *Server) CallOnConnStop(connection ziface.IConnection) {
	if s.onConnStop != nil {
		println("call conn top")
		s.onConnStop(connection)
	}
}
